package com.engine.query.cmd;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.engine.core.dao.CodeResourceMapper;
import com.engine.core.domain.GenTable;
import com.engine.core.domain.GenTableColumn;
import com.engine.core.gen.DbPlayload;
import com.engine.core.gen.Mysql;
import com.engine.core.gen.ParamOption;
import com.engine.core.interceptor.JdbcCommandContext;
import com.engine.core.interceptor.ResponseCommand;
import com.engine.core.rowMapper.WhereBuildBiz;
import com.engine.core.util.QueryUtil;
import com.engine.core.util.Response;
import com.engine.core.util.Utils;
import com.engine.dialect.DialectType;
import com.engine.system.User;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

public class QueryResourceCommand extends ResponseCommand {

    public QueryResourceCommand(User user, Map<String, Object> params) {
        super(user, params);
    }

    public static  class Playload extends DbPlayload<QueryResourceCommand.Playload> {
        public Playload(boolean isQuery) {
            super(isQuery);
        }

        private Playload(User user) {
            super(true,user);
        }


        public static QueryResourceCommand.Playload newInstance(User user){
            QueryResourceCommand.Playload playload=new QueryResourceCommand.Playload(user);
            playload.queryParamsForce=true;
            return playload;
        }

        /**
         * @return
         */
        @Override
        public Map<String, Object> getParams() {
            Map<String,Object> params=new HashMap<>();
            params.put(QueryUtil.QUERY_FETHCHRESULT,fethchResult?"1":"0");
            params.put(QueryUtil.QUERY_CONTENT,bodyContent);
            return params;
        }




        /**
         * @param commandContext
         * @return
         * @throws Exception
         */
        @Override
        public Response execute(JdbcCommandContext commandContext) throws Exception {
            return new QueryResourceCommand(user,this.getParams()).execute(commandContext);
        }
    }

    private static class GroupItem {
        String groupName;
        boolean emptyTrue;
        String whereStr;

        String sourceWhereStr;


        public GroupItem(String sourceWhereStr) {
            this.sourceWhereStr = sourceWhereStr;
        }

        public GroupItem(String sourceWhereStr,boolean emptyTrue) {
            this.emptyTrue = emptyTrue;
            this.sourceWhereStr = sourceWhereStr;
        }

        public GroupItem(String groupName, String sourceWhereStr) {
            this.groupName = groupName;
            this.sourceWhereStr = sourceWhereStr;
        }

        public GroupItem(String groupName, String sourceWhereStr, boolean emptyTrue) {
            this.groupName = groupName;
            this.emptyTrue = emptyTrue;
            this.sourceWhereStr = sourceWhereStr;
        }
    }

    /**
     * @param commandContext
     * @return
     * @throws Exception
     */
    @Override
    public Response execute(JdbcCommandContext commandContext) throws Exception {
        try {
            LinkedHashMap<String,Object> valueStack=new LinkedHashMap<>();
            LinkedHashMap<String, Set<String>> paramColumnMap=new LinkedHashMap<>();
            Map<String,String> columnAliasMap=new HashMap<>();
            Map<String,String> paramTypeMap=new HashMap<>();
            Map<String,String> functionMap=new HashMap<>();
            params.put(QueryUtil.QUERY_PARAMS_URLENCODE,"0");
            ParamOption paramOption=new ParamOption(params);
            JSONObject paramRoot=JSONObject.parseObject((String)params.get(QueryUtil.QUERY_CONTENT));
            String columns=Utils.nullDefault(Utils.urlDecode(paramRoot.getString(QueryUtil.QUERY_COLUMNS),paramOption),"*");
            String where= Utils.urlDecode(paramRoot.getString(QueryUtil.QUERY_WHERE),paramOption);

            String orderBy= Utils.urlDecode(paramRoot.getString(QueryUtil.QUERY_ORDERBY),paramOption);
            String groupBy= Utils.urlDecode(paramRoot.getString(QueryUtil.QUERY_GROUPBY),paramOption);
            String having= Utils.urlDecode(paramRoot.getString(QueryUtil.QUERY_HAVING),paramOption);
            String params= Utils.urlDecode(paramRoot.getString(QueryUtil.QUERY_PARAMS),paramOption);
            String resourceId=Utils.urlDecode(paramRoot.getString(QueryUtil.QUERY_RESOURCE),paramOption);
            DialectType dialectType=commandContext.getDialectType();



            List<GroupItem> whereGroupList=new ArrayList<>();

//            if(StringUtils.isNotBlank(params)){
//                if(StringUtils.isNotBlank(where)){ //使用param里面的值,替换where的参数
//                    JSON whereJson=Utils.getJSON(where);
//                    Utils.replaceWhereJson(whereJson,replaceByName,replaceBakName,JSON.parseObject(params));
//                    where=whereJson.toJSONString();
//                }
//            }

            List<String> whereGroupKeys=paramRoot.keySet().stream().filter(t->t.startsWith("where_")).collect(Collectors.toList());
            for (String whereGroupKey :whereGroupKeys) {
                JSON whereJson=Utils.getJSON(paramRoot.getString(whereGroupKey));
//                Utils.replaceWhereJson(whereJson,replaceByName,replaceBakName,JSON.parseObject(params));
                String whereGroup=whereJson.toJSONString();
                if(paramRoot.containsKey(whereGroupKey+"#emptyTrue")){
                    whereGroupList.add(new GroupItem(whereGroupKey,whereGroup,Utils.getBoolean(paramRoot.getString("where#emptyTrue"),false)));
                }else{
                    whereGroupList.add(new GroupItem(whereGroupKey,whereGroup));
                }
            }

            String sqlWhere="";
            String sqlColumn="";
            String sqlOrderBy="";
            String sqlGroupBy="";
            String sqlHaving="";
            Map<String,String> paramMap=new HashMap<>();


            CodeResourceMapper codeResourceMapper=commandContext.getApplicationContext().getBean(CodeResourceMapper.class);
            String[] dateformat=commandContext.getGlobal().getDateformat();
            GenTable genTable=codeResourceMapper.getGenTable(Utils.getInt(resourceId,-1));
            String columnsAlias="";
            if(genTable.getResourceType()==2 && genTable.getReplaceMode()==0){
                columnsAlias="sql_";
            }else if(Arrays.asList(0,1).contains(genTable.getResourceType())){
                columnsAlias="tbl_";
            }
            Iterator<GenTableColumn> columnListIterator=genTable.getColumns().iterator();
            while(columnListIterator.hasNext()){
                 GenTableColumn genTableColumn=columnListIterator.next();
                 if(StringUtils.isNotBlank(genTableColumn.getColumnAlias())){
                     columnAliasMap.put(genTableColumn.getColumnName(),genTableColumn.getColumnAlias());
                 }
                 if(StringUtils.isBlank(genTableColumn.getJavaType())){
                     paramTypeMap.put(genTableColumn.getColumnName(), Mysql.javaTypeByColumnType(genTableColumn.getColumnType()));
                 }else{
                     paramTypeMap.put(genTableColumn.getColumnName(),genTableColumn.getJavaType());
                 }
            }


            if(StringUtils.isNotBlank(columns)){
                if(JSON.isValidArray(columns)){
                    sqlColumn=WhereBuildBiz.repaceColumns(JSONArray.parseArray(columns,Feature.OrderedField),columnAliasMap,functionMap);
                }else{
                    sqlColumn=columns;
                }
            }


            if(StringUtils.isNotBlank(where)){
                sqlWhere=WhereBuildBiz.buildWhere((JSON) JSON.parse(where, Feature.OrderedField),columnAliasMap,dialectType);
            }
            for (int i = 0; i < whereGroupList.size(); i++) {
                GroupItem groupItem=whereGroupList.get(i);
                groupItem.whereStr=WhereBuildBiz.buildWhere((JSON) JSON.parse(groupItem.sourceWhereStr, Feature.OrderedField),columnAliasMap,dialectType);
            }


            if(StringUtils.isNotBlank(orderBy)){
                sqlOrderBy=WhereBuildBiz.repaceOrder(JSONArray.parseArray(orderBy,Feature.OrderedField));
            }

            if(StringUtils.isNotBlank(groupBy)){
                sqlGroupBy=WhereBuildBiz.repaceGroupBy(JSONArray.parseArray(groupBy,Feature.OrderedField),columnAliasMap);
            }

            if(StringUtils.isNotBlank(having)){
                sqlHaving=WhereBuildBiz.buildWhere(JSONObject.parseObject(having, Feature.OrderedField),columnAliasMap,dialectType);
            }

            if(StringUtils.isNotBlank(params)){
                paramMap=WhereBuildBiz.repaceParams(JSONObject.parseObject(params,Feature.OrderedField),valueStack,dateformat);
            }

            // 由原来的列+多个参数名 转为参数名+列 将参数名和列名做一个映射
            Map<String,String> paramColumnMapFlat=new HashMap<>();
            Iterator<Map.Entry<String,Set<String>>>  paramColumnMapEntryIterator=paramColumnMap.entrySet().iterator();
            while(paramColumnMapEntryIterator.hasNext()){
                Map.Entry<String,Set<String>> paramColumnMapEntry=paramColumnMapEntryIterator.next();
                paramColumnMapEntry.getValue().forEach(res->{
                     paramColumnMapFlat.put(res,paramColumnMapEntry.getKey());
                });
            }

            Map<String,GenTableColumn> resourceColumnMap=genTable.getColumns().stream().collect(Collectors.toMap(s->s.getColumnName(),s->s));
            Map<String,Object> dataValues=new HashMap<>();

            dataValues.putAll(valueStack);

            QueryListCommand.Playload playload= QueryListCommand.Playload.newInstance(user).isConvertParam(false).isMapParam(true)
                    .fethchResult(Utils.getBoolean(this.params.get(QueryUtil.QUERY_FETHCHRESULT),true));

            StringBuilder fromSql=new StringBuilder();
            if(Arrays.asList(0,1).contains(genTable.getResourceType())){
                playload.from(genTable.getResourceName()).where(sqlWhere)
                        .columns(sqlColumn).orderBy(sqlOrderBy).groupBy(sqlGroupBy).having(sqlHaving).addReplacements(paramMap);
            }else if(genTable.getResourceType()==2 && genTable.getReplaceMode()==0) {
                fromSql.append("(");
                fromSql.append(genTable.getSql());
                fromSql.append(") as ");
                fromSql.append(columnsAlias);
                playload.from(fromSql.toString()).where(sqlWhere)
                        .columns(sqlColumn).orderBy(sqlOrderBy).groupBy(sqlGroupBy).having(sqlHaving).addReplacements(paramMap);
            }else if(genTable.getResourceType()==2 && genTable.getReplaceMode()==1){
                paramRoot.put(QueryUtil.QUERY_RESULT_SQL,genTable.getSql());
                playload.sql(fromSql.toString())
                        .addReplacement("$where$",sqlWhere)
                        .addReplacement("$columns$",sqlColumn)
                        .addReplacement("$orderBy$",sqlOrderBy)
                        .addReplacement("$groupBy$",sqlGroupBy)
                        .addReplacement("$having$",sqlHaving)
                        .addReplacements(paramMap);

                for (int i = 0; i < whereGroupList.size(); i++) {
                    GroupItem groupItem=whereGroupList.get(i);
                    if(groupItem.whereStr==null || groupItem.whereStr.length()>0){
                        playload.addReplacement("$"+groupItem.groupName+"$",groupItem.whereStr);
                    }else{
                        if(!groupItem.emptyTrue){
                            playload.addReplacement("$"+groupItem.groupName+"$","1<>1");
                        }else{
                            playload.addReplacement("$"+groupItem.groupName+"$","1=1");
                        }
                    }
                }
            }
            return playload.addParams(dataValues).execute(commandContext);
        } catch (Exception e) {
           return Response.static_fail(500).setMsg("执行异常").setErr(e);
        }
    }
}
